package com.young.hzh_learning

import android.content.Context
import android.content.res.AssetFileDescriptor
import android.media.AudioAttributes
import android.media.AudioManager
import android.media.SoundPool
import android.media.SoundPool.OnLoadCompleteListener
import java.io.FileDescriptor

/**
 * @author huangzehui
 * @date 2024/8/7 19:26 周三
 * @description SoundPool 辅助类
 *
 * 注意：
 * 调用 load，立刻调 play，很大概率是否无法播放的，首次的可以监听 OnLoadCompleteListener 来播放
 * 获取提前 load，后续的直接播放即可
 *
 * https://blog.csdn.net/qq_28261343/article/details/82818868
 * https://cloud.tencent.com/developer/ask/sof/109309090
 *
 * https://www.cnblogs.com/tgyf/p/4740003.html
 */
object SoundPoolUtil {

    /**
     * 创建一个声音播放池
     *
     * @param maxStreams 同时播放流的最大数量，当播放的流的数目大于此值，则会选择性停止优先级较低的流
     */
    @JvmStatic
    fun createSoundPool(maxStreams: Int): SoundPool {
        val poolBuilder = SoundPool.Builder()
            .setMaxStreams(maxStreams) // 同时播放流的最大数量，当播放的流的数目大于此值，则会选择性停止优先级较低的流

        val builder = AudioAttributes.Builder()
        // Android手机上提供音频管理策略，按下音量键我们会发现由媒体声音管理，闹铃声音管理，通话声音管理等等，当系统有多个进程需要播放音频的时候，
        // 管理策略会决定最终的呈现效果，该参数的可选值将以常量的形式定义在类AudioManager中，
        builder.setLegacyStreamType(AudioManager.STREAM_MUSIC)
        // 设置用途
        builder.setUsage(AudioAttributes.USAGE_MEDIA)
        // 设置内容类型
        builder.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)

        return poolBuilder.setAudioAttributes(builder.build()).build()
    }

    /**
     * 加载音频
     *
     * @param soundPool 声音池
     * @param path 音频路径
     * @param priority 优先级
     * @param listener 加载完成监听
     *
     * @return soundID, 音频的播放 id，用于给 play 方法调用
     */
    fun load(
        soundPool: SoundPool, path: String?,
        priority: Int,
        listener: OnLoadCompleteListener? = null
    ): Int {
        if (path.isNullOrBlank()) {
            return -1
        }
        if (listener != null) {
            soundPool.setOnLoadCompleteListener(listener)
        }
        return soundPool.load(path, priority)
    }

    /**
     * 加载音频
     *
     * @param soundPool 声音池
     * @param fd 文件描述符
     * @param offset 播放的偏移量
     * @param length 播放的长度
     * @param priority 优先级
     * @param listener 加载完成监听
     *
     * @return soundID, 音频的播放 id，用于给 play 方法调用
     */
    fun load(
        soundPool: SoundPool,
        fd: FileDescriptor?,
        offset: Long,
        length: Long,
        priority: Int,
        listener: OnLoadCompleteListener? = null
    ): Int {
        if (fd == null) {
            return -1
        }
        if (listener != null) {
            soundPool.setOnLoadCompleteListener(listener)
        }
        return soundPool.load(fd, offset, length, priority)
    }

    /**
     * 加载音频
     *
     * @param soundPool 声音池
     * @param context 上下文
     * @param resId 声音的资源文件id
     * @param priority 优先级
     * @param listener 加载完成监听
     *
     * @return soundID, 音频的播放 id，用于给 play 方法调用
     */
    fun load(
        soundPool: SoundPool, context: Context, resId: Int, priority: Int,
        listener: OnLoadCompleteListener? = null
    ): Int {
        if (listener != null) {
            soundPool.setOnLoadCompleteListener(listener)
        }
        return soundPool.load(context, resId, priority)
    }

    /**
     * 加载音频
     *
     * @param soundPool 声音池
     * @param afd asset的文件描述符
     * @param priority 优先级
     * @param listener 加载完成监听
     *
     * @return soundID, 音频的播放 id，用于给 play 方法调用
     */
    fun load(
        soundPool: SoundPool,
        afd: AssetFileDescriptor?,
        priority: Int,
        listener: OnLoadCompleteListener? = null
    ): Int {
        if (afd == null) {
            return -1
        }
        if (listener != null) {
            soundPool.setOnLoadCompleteListener(listener)
        }
        return soundPool.load(afd, priority)
    }


    /**
     * 播放音频
     *
     * @param soundPool 声音池
     * @param soundID 音频的播放 id（load方法返回的值,指向某个已加载的音频资源）
     * @param leftVolume 最小音量，用来这种左右声道的值.范围 0.0f ~ 1.0f
     * @param rightVolume 最大音量，用来这种左右声道的值.范围 0.0f ~ 1.0f
     * @param priority 流的优先级，值越大优先级高，影响当同时播放数量超出了最大支持数时SoundPool对该流的处理
     * @param loop 循环播放的次数, 0为只播放一次，-1为无限循环，其他值为播放loop+1次（例如，3为一共播放4次）
     * @param rate 播放的速率，范围0.5-2.0（0.5为一半速率，1.0为正常速率，2.0为两倍速率）
     *
     * @return streamID 流 id，可用来暂停等操作
     *
     *
     * A、play()函数传递的是一个load()方法返回的soundID——指向一个被加载的音频资源，如果播放成功则返回一个非0的streamID——指向一个成功播放的流；同一个soundID可以通过多次调用play()而获得多个不同的streamID (只要不超出同时播放的最大数量)；
     *
     * B、pause()、resume()及stop()是针对播放流操作的，传递的是play()返回的streamID；
     *
     * C、play()中的priority参数，只在同时播放的流的数量超过了预先设定的最大数量时才会起作用，管理器将自动终止优先级低的播放流。如果存在多个同样优先级的流，再进一步根据其创建事件来处理，新创建的流的年龄是最小的，将最先被终止；
     *
     * D、无论如何，程序退出时，手动终止播放并释放资源是必要的；
     *
     */
    fun play(
        soundPool: SoundPool, soundID: Int, leftVolume: Float, rightVolume: Float,
        priority: Int, loop: Int, rate: Float
    ): Int {
        return soundPool.play(soundID, leftVolume, rightVolume, priority, loop, rate)
    }

    /**
     * 停止声音
     *
     * @param soundPool 声音池
     * @param streamID 流的 id，从 play 中返回
     */
    fun stop(soundPool: SoundPool?, streamID: Int) {
        if (soundPool == null) {
            return
        }
        soundPool.stop(streamID)
    }

    /**
     * 自动暂停
     *
     * @param soundPool 声音池
     */
    fun autoPause(soundPool: SoundPool?) {
        if (soundPool == null) {
            return
        }
        soundPool.autoPause()
    }

    /**
     * 自动恢复播放
     *
     * @param soundPool 声音池
     */
    fun autoResume(soundPool: SoundPool?) {
        if (soundPool == null) {
            return
        }
        soundPool.autoResume()
    }


    /**
     * 释放声音池
     * @param soundPool 声音池
     */
    fun release(soundPool: SoundPool?) {
        if (soundPool == null) {
            return
        }
        soundPool.setOnLoadCompleteListener(null)
        soundPool.release()
    }

    /**
     * 恢复声音
     * @param soundPool 声音池
     * @param streamID 流的 id，从 play 中返回
     */
    fun resume(soundPool: SoundPool?, streamID: Int) {
        soundPool?.resume(streamID)
    }

    /**
     * 暂停声音
     * @param soundPool 声音池
     * @param streamID 流的 id，从 play 中返回
     */
    fun pause(soundPool: SoundPool?, streamID: Int) {
        soundPool?.pause(streamID)
    }

}